/*
 * @Author: Jiraiya
 * @Date: 2020-05-06 11:02:58
 * @LastEditors: Jiraiya
 * @LastEditTime: 2020-05-07 16:21:35
 * @Description: 
 */
'use strict';

const path = require('path')
const next = require('next')
const Koa = require('koa2')
const Loader = require('./Loader')
const utils = require('./utils')
const bee = global.bee;

class BeeApp{
    
    constructor({port, root, apiRoot}){
        this.systemConfig = {};
        this.plugins = {};
        this.middlewareMap = new Map();
        this.serverMap = new Map();

        this.root = root;
        this.apiRoot = bee.apiRoot = apiRoot;
        this.env = process.env.NODE_ENV || 'production';
        this.port = parseInt(port || process.env.port, 10);

        this.loader = new Loader({root, env: this.env})
        this.koaApp = new Koa();
        this.nextApp = null;
        this.nextHandle = null;
        this.bee = bee;
    }

    /**
     * @description: 获取系统配置
     * @param {type} 
     * @return: 
     */    
    getSystemConfig(key){
        return this.systemConfig[key];
    }

    /**
     * @description: 获取其他配置
     * @param {type} 
     * @return: 
     */
    getPlugin(key){
        return this.plugins[key];
    }
    
    /**
     * @description: 加载收集相关配置
     * @param {type} 
     * @return: 
     */
    _load(){
        this.systemConfig = this.bee.systemConfig = this.loader.loadSystemConfig();
        this.plugins = this.bee.plugins = this.loader.loadPlugin();
        this.middlewareMap  = this.loader.loadMiddleware();
        this.serverMap = this.loader.loadService();
    }

    /**
     * @description: 加载中间件
     * @param {type} 
     * @return: 
     */    
    _attachMiddlewareList(){
        const {plugins, koaApp, nextApp, nextHandle, middlewareMap} = this;
        const middlewareList = plugins.middlewareList || [];
        middlewareList.map(conf => {
            const name = conf.package || conf.name;
            const options = Object.assign({koaApp, nextApp, nextHandle}, conf.options || {});
            const fileName = conf.package || middlewareMap.get(name);
            const fn = require(fileName);
            this._useMiddleware(fn, options);
        })        
    }

    /**
     * @description: koa挂载中间件
     * @param {type} 
     * @return: 
     */
    _useMiddleware(middleware, options){
        const fn = middleware(options);
        this.koaApp.use( fn );
    }

    /**
     * @description: 等待next启动
     * @param {type} 
     * @return: 
     */    
    async next(){
        const nextApp = this.nextApp = next({dev: this.env});
        const handle = this.nextHandle = nextApp.getRequestHandler();
        await nextApp.prepare();
    }

    /**
     * @description: 服务启动前置hooks
     * @param {type} 
     * @return: 
     */    
    async beforeHooks(){
        const hooks = this.getPlugin('beforeHooks') || [];
        const executeArr = hooks.map(p => p());
        executeArr.push(new Promise((res, rej)=> setTimeout(res, 1000)));
        return Promise.race(executeArr);
    }

    /**
     * @description: 启动服务
     * @param {type} 
     * @return: 
     */    
    async run(){
        const {koaApp, port} = this;
        this._load();
        await this.next();
        this._attachMiddlewareList();

        //触发服务前的广播
        try{
            await this.beforeHooks();
        }catch(err){
            bee.logger.error(`执行 服务前置hooks 出错：`, err);
        }

        koaApp.listen(port, ()=>{
            console.log(`http://localhost:${port}`)
        })
    }
}

module.exports = BeeApp;